contents

๐ŸŒ€ ์ฝ”๋”ฉ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•œ ์žฌ๊ท€(Recursion) & ๋ฐฑํŠธ๋ž˜ํ‚น(Backtracking) ๊ฐ€์ด๋“œ

์—ฌ๊ธฐ์„œ๋Š” ๊ฐœ๋…, ์ฐจ์ด์ , ๋Œ€ํ‘œ ๋ฌธ์ œ ์œ ํ˜•, Java ์Šคํƒ€์ผ ์ฝ”๋“œ ์˜ˆ์ œ๋กœ ์žฌ๊ท€์™€ ๋ฐฑํŠธ๋ž˜ํ‚น์„ ๊นŠ์ด ์žˆ๊ฒŒ ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค.


1. ์žฌ๊ท€(Recursion)๋ž€?

์ •์˜:
ํ•จ์ˆ˜๊ฐ€ ์ž๊ธฐ ์ž์‹ ์„ ํ˜ธ์ถœํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ๋” ์ž‘์€ ํ•˜์œ„ ๋ฌธ์ œ๋กœ ์ชผ๊ฐœ์–ด ํ•ด๊ฒฐํ•˜๋Š” ๊ธฐ๋ฒ•์ž…๋‹ˆ๋‹ค.

์˜ˆ์ œ โ€“ ํŒฉํ† ๋ฆฌ์–ผ

int factorial(int n) {
    if (n == 0) return 1;          // ๊ธฐ์ € ์กฐ๊ฑด
    return n * factorial(n - 1);   // ์žฌ๊ท€ ํ˜ธ์ถœ
}

Dry Run (n=3):


2. ๋ฐฑํŠธ๋ž˜ํ‚น(Backtracking)์ด๋ž€?

์ •์˜:
๋ชจ๋“  ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ์˜ ์ˆ˜(์„ ํƒ์ง€)๋ฅผ ํƒ์ƒ‰ํ•˜๋ฉด์„œ, ์กฐ๊ฑด์— ๋งž์ง€ ์•Š์œผ๋ฉด ๋˜๋Œ์•„๊ฐ€์„œ(Backtrack) ๋‹ค๋ฅธ ๊ธธ์„ ์ฐพ๋Š” ๋ฐฉ์‹์˜ ์žฌ๊ท€ ํƒ์ƒ‰ ๊ธฐ๋ฒ•์ž…๋‹ˆ๋‹ค.


3. ์žฌ๊ท€ vs ๋ฐฑํŠธ๋ž˜ํ‚น


4. ๋Œ€ํ‘œ ๋ฐฑํŠธ๋ž˜ํ‚น ๋ฌธ์ œ & ์ฝ”๋“œ

a. N-Queen ๋ฌธ์ œ

void solveNQueens(int n) {
    List<List<String>> solutions = new ArrayList<>();
    char[][] board = new char[n][n];
    for (char[] row : board) Arrays.fill(row, '.');
    backtrack(board, 0, solutions);
}

void backtrack(char[][] board, int row, List<List<String>> solutions) {
    if (row == board.length) {
        solutions.add(boardToList(board));
        return;
    }
    for (int col = 0; col < board.length; col++) {
        if (isValid(board, row, col)) {
            board[row][col] = 'Q';
            backtrack(board, row + 1, solutions);
            board[row][col] = '.'; // ์ƒํƒœ ๋ณต์›
        }
    }
}

boolean isValid(char[][] board, int row, int col) {
    for (int i = 0; i < row; i++)
        if (board[i][col] == 'Q') return false;
    for (int i = row-1, j = col-1; i>=0 && j>=0; i--, j--)
        if (board[i][j] == 'Q') return false;
    for (int i = row-1, j = col+1; i>=0 && j<board.length; i--, j++)
        if (board[i][j] == 'Q') return false;
    return true;
}

b. ์Šค๋„์ฟ  ํ•ด๊ฒฐ

boolean solveSudoku(char[][] board) {
    for (int i = 0; i < 9; i++)
        for (int j = 0; j < 9; j++)
            if (board[i][j] == '.') {
                for (char c = '1'; c <= '9'; c++) {
                    if (isValid(board, i, j, c)) {
                        board[i][j] = c;
                        if (solveSudoku(board)) return true;
                        board[i][j] = '.'; // ๋ฐฑํŠธ๋ž˜ํ‚น
                    }
                }
                return false;
            }
    return true;
}

boolean isValid(char[][] b, int r, int c, char num) {
    for (int i = 0; i < 9; i++) {
        if (b[r][i] == num || b[i][c] == num) return false;
        if (b[3*(r/3)+i/3][3*(c/3)+i%3] == num) return false;
    }
    return true;
}

c. ๋ถ€๋ถ„์ง‘ํ•ฉ ์ƒ์„ฑ

List<List<Integer>> subsets(int[] nums) {
    List<List<Integer>> res = new ArrayList<>();
    backtrack(nums, 0, new ArrayList<>(), res);
    return res;
}

void backtrack(int[] nums, int start, List<Integer> track, List<List<Integer>> res) {
    res.add(new ArrayList<>(track));
    for (int i = start; i < nums.length; i++) {
        track.add(nums[i]);
        backtrack(nums, i+1, track, res);
        track.remove(track.size()-1);
    }
}

d. ์ˆœ์—ด ์ƒ์„ฑ

List<List<Integer>> permute(int[] nums) {
    List<List<Integer>> res = new ArrayList<>();
    backtrack(nums, new ArrayList<>(), new boolean[nums.length], res);
    return res;
}

void backtrack(int[] nums, List<Integer> track, boolean[] used, List<List<Integer>> res) {
    if (track.size() == nums.length) {
        res.add(new ArrayList<>(track));
        return;
    }
    for (int i = 0; i < nums.length; i++) {
        if (!used[i]) {
            track.add(nums[i]);
            used[i] = true;
            backtrack(nums, track, used, res);
            track.remove(track.size()-1);
            used[i] = false;
        }
    }
}

e. ๋‹จ์–ด ์ฐพ๊ธฐ (Word Search)

boolean exist(char[][] board, String word) {
    for (int i = 0; i < board.length; i++)
        for (int j = 0; j < board[0].length; j++)
            if (dfs(board, word, i, j, 0)) return true;
    return false;
}

boolean dfs(char[][] board, String word, int i, int j, int idx) {
    if (idx == word.length()) return true;
    if (i<0 || j<0 || i>=board.length || j>=board[0].length || board[i][j] != word.charAt(idx))
        return false;

    char tmp = board[i][j];
    board[i][j] = '#';
    boolean found = dfs(board, word, i+1, j, idx+1) ||
                    dfs(board, word, i-1, j, idx+1) ||
                    dfs(board, word, i, j+1, idx+1) ||
                    dfs(board, word, i, j-1, idx+1);
    board[i][j] = tmp; // ์ƒํƒœ ๋ณต์›
    return found;
}

5. ๋ฐฑํŠธ๋ž˜ํ‚น ํ…œํ”Œ๋ฆฟ

void backtrack(...) {
    if (ํ•ด๋‹ต ์กฐ๊ฑด ์ถฉ์กฑ) {
        ์ €์žฅ/์ถœ๋ ฅ;
        return;
    }
    for (๊ฐ€๋Šฅํ•œ ์„ ํƒ : ๋ชจ๋“  ํ›„๋ณด) {
        if (์กฐ๊ฑด ๊ฒ€์ฆ) {
            ์ƒํƒœ ๋ณ€๊ฒฝ;
            backtrack(...);
            ์ƒํƒœ ๋ณต์›;
        }
    }
}

6. ํ•ต์‹ฌ ํŒ


7. ์‚ฌ์šฉ ์‹œ์ 


8. ๋ณต์žก๋„

๋Œ€๋ถ€๋ถ„ ์ง€์ˆ˜ ์‹œ๊ฐ„ ๋ณต์žก๋„ O(kโฟ) ๋˜๋Š” O(n!)
โ†’ ๊ฐ€์ง€์น˜๊ธฐยท๋ฉ”๋ชจ์ด์ œ์ด์…˜์œผ๋กœ ๊ฐ€๋Šฅํ•˜๋ฉด ์ค„์ด๊ธฐ


9. ์š”์•ฝ ํ‘œ

์œ ํ˜• ์˜ˆ์‹œ ์ ‘๊ทผ
๋‹จ์ˆœ ์žฌ๊ท€ ํŒฉํ† ๋ฆฌ์–ผ, ํ”ผ๋ณด๋‚˜์น˜ ๊ธฐ์ € ์กฐ๊ฑด & ์ž๊ธฐ ํ˜ธ์ถœ
๋ถ€๋ถ„์ง‘ํ•ฉ โ†’ ๋ชจ๋“  ๋ถ€๋ถ„์ง‘ํ•ฉ ์„ ํƒ/๋น„์„ ํƒ ์žฌ๊ท€ ํƒ์ƒ‰
์ˆœ์—ด โ†’ ๋ชจ๋“  ์ˆœ์—ด used[]๋กœ ์ค‘๋ณต ๋ฐฉ์ง€, ๋ฐฑํŠธ๋ž˜ํ‚น
๋ณด๋“œ ํผ์ฆ N-Queen, Sudoku ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ํ›„ ๋ฐฐ์น˜ยท๋ณต๊ตฌ ๋ฐ˜๋ณต
๊ฒฝ๋กœ ํƒ์ƒ‰ ๋‹จ์–ด์ฐพ๊ธฐ, ๋ฏธ๋กœ ํƒ์ƒ‰ DFS, ๋ฐฉ๋ฌธ ํ‘œ์‹œ, ์ƒํƒœ ๋ณต์›

๐Ÿ”ฅ ์ฝ”๋”ฉ ํ…Œ์ŠคํŠธ Recursion/Backtracking(์žฌ๊ท€/๋ฐฑํŠธ๋ž˜ํ‚น) ๋Œ€ํ‘œ ๋ฌธ์ œ & ํ’€์ด ์ •๋ฆฌ

์•„๋ž˜๋Š” LeetCodeยทํ”„๋กœ๊ทธ๋ž˜๋จธ์Šคยท๊ธฐ์—… ๋ฉด์ ‘ ๋“ฑ์—์„œ ๋งค์šฐ ์ž์ฃผ ๋“ฑ์žฅํ•˜๋Š” ์žฌ๊ท€ยท๋ฐฑํŠธ๋ž˜ํ‚น ์œ ํ˜• ๋Œ€ํ‘œ ๋ฌธ์ œ์™€ ๊ธฐ๋ณธ ํ’€์ด ์ฝ”๋“œ/ํ•ต์‹ฌ ์•„์ด๋””์–ด๋ฅผ ์ •๋ฆฌํ•œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.


1. ๋ชจ๋“  ๋ถ€๋ถ„์ง‘ํ•ฉ(Powerset) ๊ตฌํ•˜๊ธฐ

๋ฌธ์ œ:
์ •์ˆ˜ ์ง‘ํ•ฉ์ด ์ฃผ์–ด์งˆ ๋•Œ, ๋ชจ๋“  ๋ถ€๋ถ„์ง‘ํ•ฉ(ํŒŒ์›Œ์…‹)์„ ๋ฐ˜ํ™˜ํ•˜์„ธ์š”.

ํ’€์ด:
๊ฐ ์š”์†Œ์— ๋Œ€ํ•ด โ€œํฌํ•จ/๋ถˆํฌํ•จโ€์„ ์„ ํƒํ•˜๋ฉฐ ๋ฐฑํŠธ๋ž˜ํ‚น(์žฌ๊ท€ ํƒ์ƒ‰).

void dfs(int[] nums, int idx, List<Integer> path, List<List<Integer>> res) {
    res.add(new ArrayList<>(path)); // ํ˜„์žฌ ๋ถ€๋ถ„์ง‘ํ•ฉ ์ €์žฅ
    for (int i = idx; i < nums.length; i++) {
        path.add(nums[i]);
        dfs(nums, i+1, path, res); // ๋‹ค์Œ ๋‹จ๊ณ„๋กœ ์ด๋™
        path.remove(path.size()-1); // ๋ฐฑํŠธ๋ž˜ํ‚น
    }
}

2. ์ˆœ์—ด(Permutations)

๋ฌธ์ œ:
์ˆ˜์—ด์ด ์ฃผ์–ด์งˆ ๋•Œ, ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ์ˆœ์—ด์„ ๋ฐ˜ํ™˜ํ•˜์„ธ์š”.

ํ’€์ด:
์žฌ๊ท€ + used[] ๋ฐฐ์—ด๋กœ ์ค‘๋ณต ๋ฐฉ์ง€. ์‚ฌ์šฉ ์•ˆํ•œ ์š”์†Œ๋งˆ๋‹ค ์ƒˆ๋กœ์šด ์ž๋ฆฌ์— ์‹œ๋„.

void dfs(int[] nums, List<Integer> path, boolean[] used, List<List<Integer>> res) {
    if (path.size() == nums.length) res.add(new ArrayList<>(path));
    else {
        for (int i = 0; i < nums.length; i++) {
            if (!used[i]) {
                used[i] = true;
                path.add(nums[i]);
                dfs(nums, path, used, res);
                path.remove(path.size()-1); // ๋ฐฑํŠธ๋ž˜ํ‚น
                used[i] = false;
            }
        }
    }
}

3. N-Queen

๋ฌธ์ œ:
Nร—N ์ฒด์ŠคํŒ์— ์„œ๋กœ๊ฐ€ ๊ณต๊ฒฉํ•˜์ง€ ์•Š๋Š” N๊ฐœ์˜ ํ€ธ์„ ๋ฐฐ์น˜ํ•˜๋Š” ๋ชจ๋“  ๊ฒฝ์šฐ(๋ฐฐ์น˜)๋ฅผ ๋ฐ˜ํ™˜ํ•˜์„ธ์š”.

ํ’€์ด:
๊ฐ ํ–‰(row)๋งˆ๋‹ค ๊ฐ€๋Šฅํ•œ ์œ„์น˜์— ํ€ธ์„ ๋†“๊ณ , ์œ ํšจ์„ฑ ์ฒดํฌ(์—ด, ๋Œ€๊ฐ์„ ).
ํ€ธ์„ ๋†“๊ณ  ๋‹ค์Œ ํ–‰ ์ง„ํ–‰, ๋ถˆ๊ฐ€๋Šฅํ•˜๋ฉด ๋˜๋Œ๋ฆผ (๋ฐฑํŠธ๋ž˜ํ‚น).

void dfs(char[][] board, int row, List<List<String>> res) {
    if (row == board.length) res.add(boardToList(board));
    else {
        for (int col = 0; col < board.length; col++) {
            if (isValid(board, row, col)) {
                board[row][col] = 'Q';
                dfs(board, row+1, res);
                board[row][col] = '.'; // ๋ฐฑํŠธ๋ž˜ํ‚น
            }
        }
    }
}

4. ์Šค๋„์ฟ (Sudoku) ํ’€์ด

๋ฌธ์ œ:
9ร—9 ์Šค๋„์ฟ  ํผ์ฆ(๊ณต๋ฐฑ: '.')์„ ์ฑ„์šฐ์„ธ์š”.

ํ’€์ด:
๋ชจ๋“  ์…€์— 1~9 ์ˆซ์ž ์‹œ๋„, ์œ ํšจ(ํ–‰/์—ด/์นธ ์ฒดํฌ)ํ•˜๋ฉด ์žฌ๊ท€ ์ง„ํ–‰, ๋ถˆ๊ฐ€๋Šฅํ•˜๋ฉด ๋˜๋Œ๋ฆผ.

boolean solve(char[][] board) {
    for (int r = 0; r < 9; r++)
        for (int c = 0; c < 9; c++)
            if (board[r][c] == '.') {
                for (char num = '1'; num <= '9'; num++)
                    if (isValid(board, r, c, num)) {
                        board[r][c] = num;
                        if (solve(board)) return true;
                        board[r][c] = '.'; // ๋ฐฑํŠธ๋ž˜ํ‚น
                    }
                return false;
            }
    return true;
}

5. Word Search (๋‹จ์–ด์ฐพ๊ธฐ/๊ฒฉ์ž ๊ฒฝ๋กœ์ฐพ๊ธฐ)

๋ฌธ์ œ:
2์ฐจ์› ๋ฌธ์žํŒ(board)๊ณผ ๋‹จ์–ด(word)๊ฐ€ ์ฃผ์–ด์งˆ ๋•Œ, ์ธ์ ‘(์ƒํ•˜์ขŒ์šฐ) ์…€์„ ๋”ฐ๋ผ ํ•ด๋‹น ๋‹จ์–ด๋ฅผ ์™„์„ฑํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํŒ๋ณ„ํ•˜์„ธ์š”.

ํ’€์ด:
๋ชจ๋“  ์…€ ์‹œ์ž‘์ ์—์„œ DFS+๋ฐฑํŠธ๋ž˜ํ‚น. ๋ฐฉ๋ฌธ์ฒดํฌ, ๋„ค ๋ฐฉํ–ฅ ์žฌ๊ท€, ์‹คํŒจ ์‹œ ์›์ƒ๋ณต๊ตฌ.

boolean dfs(char[][] board, String word, int i, int j, int idx) {
    if (idx == word.length()) return true;
    if (i<0 || j<0 || i>=board.length || j>=board[0].length || board[i][j] != word.charAt(idx)) return false;
    char tmp = board[i][j]; board[i][j] = '#';
    boolean found = dfs(board, word, i+1, j, idx+1) ||
                    dfs(board, word, i-1, j, idx+1) ||
                    dfs(board, word, i, j+1, idx+1) ||
                    dfs(board, word, i, j-1, idx+1);
    board[i][j] = tmp; return found;
}

6. Combination Sum / Subset Sum

๋ฌธ์ œ:
์ •์ˆ˜ candidates์™€ target์ด ์ฃผ์–ด์งˆ ๋•Œ, ๊ฐ ์›์†Œ๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ•ฉ์ด target์ด ๋˜๋Š” ๋ชจ๋“  ์กฐํ•ฉ์„ ๊ตฌํ•˜์„ธ์š”.

ํ’€์ด:
๊ฐ ์›์†Œ๋ฅผ ๊ณ ๋ฅด๊ฑฐ๋‚˜, ์Šคํ‚ตํ•˜๊ฑฐ๋‚˜. ์„ ํƒ์‹œ target ๊ฐ์†Œ, ๋ฐฑํŠธ๋ž˜ํ‚น.

void dfs(int[] candidates, int target, int idx, List<Integer> path, List<List<Integer>> res) {
    if (target == 0) res.add(new ArrayList<>(path));
    else if (target > 0) {
        for (int i = idx; i < candidates.length; i++) {
            path.add(candidates[i]);
            dfs(candidates, target-candidates[i], i, path, res); // ๊ฐ™์€ ๊ฐ’ ์žฌ์‚ฌ์šฉ ํ—ˆ์šฉ
            path.remove(path.size()-1); // ๋ฐฑํŠธ๋ž˜ํ‚น
        }
    }
}

7. ์˜ฌ๋ฐ”๋ฅธ ๊ด„ํ˜ธ ์กฐํ•ฉ ์ƒ์„ฑ (Generate Parentheses)

๋ฌธ์ œ:
N์Œ์˜ ๊ด„ํ˜ธ(N pairs)๊ฐ€ ์ฃผ์–ด์งˆ ๋•Œ, ๋ชจ๋“  ์˜ฌ๋ฐ”๋ฅธ ์กฐํ•ฉ์„ ์ƒ์„ฑํ•˜์„ธ์š”.

ํ’€์ด:
์™ผ์ชฝ ๊ด„ํ˜ธ(open), ์˜ค๋ฅธ์ชฝ ๊ด„ํ˜ธ(close) ๊ฐœ์ˆ˜๋ฅผ ์ถ”์ . open < N์ด๋ฉด '(', close < open์ด๋ฉด ')' ์ถ”๊ฐ€. ๊ธธ์ด=2N์ด๋ฉด ๊ธฐ๋ก.

void dfs(int n, int open, int close, String path, List<String> res) {
    if (path.length() == 2*n) res.add(path);
    if (open < n) dfs(n, open+1, close, path+"(", res);
    if (close < open) dfs(n, open, close+1, path+")", res);
}

โœ… ๋ฉด์ ‘/์ฝ”ํ…Œ ์ฑ„์  ํฌ์ธํŠธ ์š”์•ฝ

๋ฌธ์ œ ์œ ํ˜• ํ•ต์‹ฌ ๋ฐฑํŠธ๋ž˜ํ‚น/์žฌ๊ท€ ๊ตฌ์กฐ ์„ค๋ช…ํ•ด์•ผ ํ•  ํฌ์ธํŠธ
๋ถ€๋ถ„์ง‘ํ•ฉ ํฌํ•จ/๋น„ํฌํ•จ ํƒ์ƒ‰, ๊ฒฝ๋กœ ์ถ”์  ์žฌ๊ท€ํŠธ๋ฆฌ, ์ƒํƒœ๋ณ€์ˆ˜ ์„ค๋ช…
์ˆœ์—ด ์ˆœ์„œ ๊ฒฝ์šฐ์˜ ์ˆ˜, used[] ํ™œ์šฉ ์ค‘๋ณต๋ฐฉ์ง€, ์ƒํƒœ ๋ณต์› ์„ค๋ช…
N-Queen ํ–‰๋ณ„ ๊ฒฐ์ •, ์œ ํšจ์„ฑ ๊ฒ€์ฆ & ๊ฐ€์ง€์น˜๊ธฐ ๋ณด๋“œ์„ค๊ณ„, ์กฐ๊ฑดํŒ์ •, ๋ฐฑํŠธ๋ž˜ํ‚น
Sudoku ์…€ ๋‹จ์œ„ ๊ฐ’ ์‹œ๋„, ์‹คํŒจ ์‹œ ๋ฐฑํŠธ๋ž™ ์ž…๋ ฅ์ˆœ์„œ, ์œ ํšจ๊ฒ€์ฆ ์ค‘์š”
Word Search DFS + ๋ฐฉ๋ฌธ์ฒดํฌ, ๋˜๋Œ๋ฆฌ๊ธฐ ํ•„์š” ๋„ค ๋ฐฉํ–ฅ ํƒ์ƒ‰, ๋ณต์›, ์œ ํšจ์„ฑ
Combination Sum ํ•ฉ์ด ๋˜๋Š” ์กฐํ•ฉ, ๋ฐ˜๋ณต ํ—ˆ์šฉ target ๊ฐ์†Œ, ๋ฐ˜๋ณต ์žฌ๊ท€ ๊ตฌ์กฐ
๊ด„ํ˜ธ ์ƒ์„ฑ '(', ')' ๊ฐœ์ˆ˜ ์กฐ๊ฑด ์ œ์–ด ๊ท ํ˜•ยท์œ ํšจ์กฐํ•ฉ, ์ƒํƒœ ์ถ”์ 

๐Ÿ’ก ํŒ

references